﻿#pragma once
#include "DataObject.h"
#include "Object.h"
#include "Types.h"

class Mesh : public Object
{
public:
  using FaceInfo = vtkm::Pair<Id, UInt8>;

  Mesh(const Configuration& cfg)
    : Object(cfg)
  {
  }
  virtual ~Mesh() = default;

  template<typename T>
  ArrayHandle<T> GetFieldArray(const std::string& name)
  {
    try
    {
      return _data_set.GetField(name).GetData().AsArrayHandle<ArrayHandle<T>>();
    }
    catch (const std::exception& e)
    {
      Error(e.what());
    }
  }


  const vtkm::cont::Field& GetField(const std::string& name) const;
  const vtkm::cont::Field& GetCellField(const std::string& name) const;
  const vtkm::cont::Field& GetPointField(const std::string& name) const;

  vtkm::cont::Field& GetField(const std::string& name);
  vtkm::cont::Field& GetCellField(const std::string& name);
  vtkm::cont::Field& GetPointField(const std::string& name);

  CoordinateSystem& GetCoordinate() { return this->_data_set.GetCoordinateSystem(); }
  const CoordinateSystem& GetCoordinate() const { return this->_data_set.GetCoordinateSystem(); }

  const auto& GetCellSet() const { return this->_data_set.GetCellSet(); }
  auto& GetCellSet() { return this->_data_set.GetCellSet(); }

  //const ArrayHandle<Id>& GetBoundaryId() const { return this->GetFieldArray<Id>("boundary_id"); }
  ArrayHandle<Id> GetBoundaryId() { return this->GetFieldArray<Id>("boundary_id"); }

  const DataSet& GetDataSet() const { return this->_data_set; }
  DataSet& GetDataSet() { return this->_data_set; }

  virtual void Build() = 0;
  /// @brief 建立Face的拓扑关系
  void BuildFaceTopo(const std::map<std::string, UInt8>& bnd_name_id);

  ArrayHandle<FaceInfo>& GetCellLinks() { return _cell_links; }
  ArrayHandle<Id>& GetFaceNumOffset() { return _face_num_offset; }
  auto& GetElementSide() { return _element_sides; }

  bool IsPrepared() { return _prepared; }
  void Prepared() { this->_prepared = true; }

  std::pair<ArrayHandle<UInt8>, ArrayHandle<FaceInfo>> FlatBoundaryInfo(
    const std::map<std::string, UInt8>& bnd_name_id);

protected:
  // 网格是否准备好
  bool _prepared = false;

  DataSet _data_set;
  //DynamicCellSet _cell_set;
  //CoordinateSystem _coord;
  //ArrayHandle<Id> _boundary_id;


  ArrayHandle<Id> _face_num_offset;

  /// @brief first: cell global id, second: face local id

  /// @brief 只存放的neighbor cell的FaceInfo，因为当前cell的FaceInfo是显式的, _cell_links[cell global id][face local id]
  ArrayHandle<FaceInfo> _cell_links;
  //vtkm::cont::ArrayHandleGroupVecVariable<FaceInfo, Id> _cell_links;

  /// @brief Face的左右单元信息
  /// left cell :  _face_links[face global id][0]  -> FaceInfo
  /// right cell : _face_links[face global id][1]  -> FaceInfo
  //ArrayHandle<Vec<FaceInfo, 2>> _face_links;

  std::map<std::string, std::vector<FaceInfo>> _element_sides;

  std::map<std::string, std::vector<int>> _bnd_map;
};
